<template>
	<view @touchstart="handleTouchStart" @touchend="handleTouchEnd" @touchmove="handleTouchMove" >
		<view ref="tts-button">
			<slot>
				<button>Sound</button>
			</slot>
		</view>
		<uni-popup ref="popup" type="bottom" background-color="#0000" @change="handlePopupChange" :safe-area="false">
			<view :class="soundClass">
				<view :class="soundPanelClass">
					<view class="view sound-panel-sound" v-if="selectState===toSoundFlag">
						<view class="view line1"></view>
						<view class="view line3"></view>
						<view class="view line2"></view>
						<view class="view line4"></view>
						<view class="view line5"></view>
						<view class="view line3"></view>
						<view class="view line4"></view>
						<view class="view line1"></view>
						<view class="view line2"></view>
					</view>
					<view class="view sound-panel-cancel" v-else-if="selectState===cancelFlag">
						<view class="view line1"></view>
						<view class="view line3"></view>
						<view class="view line2"></view>
						<view class="view line4"></view>
						<view class="view line5"></view>
					</view>
					<view class="view sound-panel-text" v-else-if="selectState===toTextFlag">
						<view class="view line1"></view>
						<view class="view line3"></view>
						<view class="view line2"></view>
						<view class="view line4"></view>
						<view class="view line5"></view>
						<!-- <text>{{voiceContent}}</text>
						<view>
							<view>
								<view class="line1"></view>
								<view class="line3"></view>
								<view class="line2"></view>
								<view class="line4"></view>
								<view class="line5"></view>
								<view class="line3"></view>
								<view class="line4"></view>
								<view class="line1"></view>
								<view class="line2"></view>
							</view>
						</view> -->
					</view>
				</view>
			</view>
			<canvas 
			canvas-id="myCanvas" 
			id="myCanvas" type="2d" 
			style="margin:0;padding:0; width: 100%; height: 250px;"
			:disable-scroll="true" />
		</uni-popup>
	</view>
</template>

<script>	
	var plugin = requirePlugin("WechatSI")
	let manager = plugin.getRecordRecognitionManager();
	const CANCEL_FLAG='left';
	const TO_TEXT_FLAG='right';
	const TO_SOUND_FLAG='bottom';
	export default {
		name: 'TTS',
		data() {
			return {
				cancelFlag: CANCEL_FLAG,
				toTextFlag: TO_TEXT_FLAG,
				toSoundFlag: TO_SOUND_FLAG,
				record: null,
				// 画板宽度
				canvasWidth: 0,
				// 画板高度
				canvasHeight: 250,
				// 屏幕高度
				screenHeight: 0,
				// 当前选择的状态
				selectState: TO_SOUND_FLAG,
				recordOption: {
					format: 'mp3'
				},
				// 语音识别的内容
				voiceContent: null,
				// 画板对象
				canvas: null,
				// 画板上下文
				ctx: null,
				// 画板尺寸
				canvasRect: {},
				// 按钮宽度
				buttonSize: 100,
			}
		},
		props: {
			leftButtonText: {
				type: String,
				default: 'cancel'
			},
			textColor: {
				type: String,
				default: 'rgb(250, 250, 250)'
			},
			actionTextColor: {
				type: String,
				default: 'rgb(30, 30, 30)'
			},
			buttonBackgroundColor: {
				type: String,
				default: 'rgb(80, 80, 80)'
			},
			actionButtonBackgroundColor: {
				type: String,
				default: 'rgb(250, 250, 250)'
			},
			buttonStrokeColor: {
				type: String,
				default: 'rgb(120, 120, 120)'
			},
			actionButtonStrokeColor: {
				type: String,
				default: 'rgb(220, 220, 220)'
			},
		},
		onLoad() {
		},
		onReady() {
			this.initRecord();
			const systemInfo = uni.getWindowInfo();
			this.canvasWidth=systemInfo.windowWidth;
			this.screenHeight=systemInfo.screenHeight;
		},
		computed: {
			soundClass: function() {
				let classList = ['sound'];
				if(this.selectState) {
					classList.push(`sound-${this.selectState}`)
				}
				return classList.join(' ');
			},
			soundPanelClass: function() {
				let classList = ['sound-panel'];
				if(this.selectState) {
					classList.push(`sound-panel-${this.selectState}`)
				}
				return classList.join(' ');
			},
			leftClipPath: function() {
				if(this.canvas) {
					const systemInfo = uni.getWindowInfo();
					const width = systemInfo.windowWidth;
					const height = 130;
					const size = this.buttonSize;
					const padding = 60;
					const path = this.canvas.createPath2D();
					path.moveTo(0,height-size);
					path.quadraticCurveTo(width*0.25-padding/2, 10, width*0.5-padding, 10);
					path.bezierCurveTo(width*0.5, size/16, width*0.5, size*15/16, width*0.5-padding, size);
					path.quadraticCurveTo(width*0.25-padding/2, height-size/2+30, 0, height);
					path.closePath();
					return path;
				} else {
					return {}
				}
			},
			rightClipPath: function() {
				if(this.canvas) {
					const systemInfo = uni.getWindowInfo();
					const width = systemInfo.windowWidth;
					const height = 130;
					const size = this.buttonSize;
					const padding = 60;
					const path = this.canvas.createPath2D();
					path.moveTo(width,height-size);
					path.quadraticCurveTo(width*0.75+padding/2, 10, width/2+padding, 10);
					path.bezierCurveTo(width/2, size/16, width*0.5, size*15/16, width*0.5+padding, size);
					path.quadraticCurveTo(width*0.75+padding/2, height-size/2+30, width, height);
					path.closePath();
					return path;
				} else {
					return {}
				}
			},
			bottomClipPath: function() {
				if(this.canvas) {
					const systemInfo = uni.getWindowInfo();
					const width = systemInfo.windowWidth;
					const height = 250;
					const size = this.buttonSize;
					const path = this.canvas.createPath2D();
					path.moveTo(0, height-size);
					path.quadraticCurveTo(width/2, size-20, width, height-size);
					path.lineTo(width, height);
					path.lineTo(0, height);
					path.closePath();
					return path;
				} else {
					return {}
				}
			}
		},
		watch: {
			selectState: function(n, o) {
				if(n===o) return;
				this.$nextTick(()=>{
					this.drawKeyword();
				});
			}
		},
		methods: {
			initCanvan() {
				const self = this;
				this.createSelectorQuery()
				    .select('#myCanvas') // 在 WXML 中填入的 id
				    .fields({ node: true, size: true })
				    .exec((res) => {
				        // Canvas 对象
				        self.canvas = res[0].node
				        // 渲染上下文
				        self.ctx = self.canvas.getContext('2d');
				        // Canvas 画布的实际绘制宽高
				        const width = res[0].width;
				        const height = res[0].height;
						self.canvasRect = {
							x: res[0].left,
							y: res[0].top,
							width: res[0].width,
							height: res[0].height
						}
				        // 初始化画布大小
				        const dpr = uni.getWindowInfo().pixelRatio;
				        self.canvas.width = width * dpr
				        self.canvas.height = height * dpr
				        self.ctx.scale(dpr, dpr);
						self.drawKeyword();
				    });
			},
			/** 根据鼠标位置计算当前选择的按钮状态 */
			calcSelectState(x, y) {
				if(!this.ctx) {
					return TO_SOUND_FLAG;
				}
				// 转化鼠标坐标系
				const mouse = this.getCanvasCoord(this.canvas, x,y);
				
				const leftClipPath = this.leftClipPath;
				if(this.ctx.isPointInPath(leftClipPath, mouse.x, mouse.y)) {
					return CANCEL_FLAG;
				} 
				const rightClipPath = this.rightClipPath;
				if(this.ctx.isPointInPath(rightClipPath, mouse.x, mouse.y)) {
					return TO_TEXT_FLAG;
				}
				const bottomClipPath = this.bottomClipPath;
				if(this.ctx.isPointInPath(bottomClipPath, mouse.x, mouse.y)) {
					return TO_SOUND_FLAG;
				}
				return this.selectState;
			},
			/** 绘制键盘 */
			drawKeyword() {
				if(this.ctx) {
					const systemInfo = uni.getWindowInfo();
					const width = systemInfo.windowWidth;
					const height = 250;
					const size = this.buttonSize;
					// 清屏
					this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
					// 绘制左侧按钮
					this.ctx.save();
					const leftClipPath = this.leftClipPath;
					let leftTextColor = this.textColor;
					if(this.selectState===CANCEL_FLAG) {
						this.ctx.fillStyle = this.actionButtonBackgroundColor;
						this.ctx.translate(0,height-size/2); // 设置缩放中心点
						this.ctx.scale(1.01, 1.01);
						this.ctx.translate(0, -(height-size/2)); // 平移回去
						leftTextColor = this.actionTextColor;
					} else {
						this.ctx.fillStyle = this.buttonBackgroundColor;
					}
					// 绘制按钮形状
					this.ctx.fill(leftClipPath);
					// 绘制文字
					const leftButtonText = this.$i18n?this.$i18n.t(this.leftButtonText):'Cancel';
					this.drawCircularText(width*0.25, height, height-10-size/2, leftButtonText, 16, leftTextColor, Math.PI*105/180, Math.PI*95/180);
					this.ctx.restore();
					
					// 绘制右侧按钮
					this.ctx.save();
					const rightClipPath = this.rightClipPath;
					let rightTextColor = this.textColor;
					if(this.selectState===TO_TEXT_FLAG) {
						this.ctx.fillStyle = this.actionButtonBackgroundColor;
						this.ctx.translate(width,height-size/2); // 设置缩放中心点
						this.ctx.scale(1.01, 1.01);
						this.ctx.translate(-width,-(height-size/2)); // 设置缩放中心点
						rightTextColor = this.actionTextColor;
					} else {
						this.ctx.fillStyle = this.buttonBackgroundColor;
					}
					this.ctx.fill(rightClipPath);
					// 绘制文字
					this.drawCircularText(width*0.62, height+150, height-10-size/2+160, '滑到这里 智能转换', 16, rightTextColor, Math.PI*88/180, Math.PI*70/180);
					this.ctx.restore();
					
					// 绘制底部按钮
					this.ctx.save();
					const bottomClipPath = this.bottomClipPath;
					let bottomTextColor = this.textColor;
					this.ctx.lineWidth = 3;
					if(this.selectState===TO_SOUND_FLAG) {
						this.ctx.fillStyle = this.actionButtonBackgroundColor;
						this.ctx.strokeStyle = this.actionButtonStrokeColor;
						this.ctx.translate(width/2,height); // 设置缩放中心点
						this.ctx.scale(1.05, 1.05);
						this.ctx.translate(-width/2,-height); // 设置缩放中心点
						bottomTextColor = this.actionTextColor;
					} else {
						this.ctx.fillStyle = this.buttonBackgroundColor;
						this.ctx.strokeStyle = this.buttonStrokeColor;
					}
					this.ctx.fill(bottomClipPath);
					this.ctx.stroke(bottomClipPath);
					this.drawCircularText(width*0.5, height+400, 500, '松开填到描述', 16, bottomTextColor, Math.PI*100/180, Math.PI*80/180);
					this.ctx.restore();
				}
			},
			drawCircularText(x, y, radius, string, fontSize, fontColor, startAngle, endAngle) {
			  const angleDecrement = (startAngle - endAngle) / (string.length - 1);
			  let angle = startAngle;
			  this.ctx.save();
			  this.ctx.fillStyle=fontColor;
			  // this.ctx.strokeStyle=TEXT_STROKE_STYLE;
			  this.ctx.font = `${fontSize}px "Microsoft YaHei"`; // 字体大小+样式
			  this.ctx.textAlign="center";
			  this.ctx.textBaseline="middle";
			
			  for (let i = 0; i < string.length; i++) {
			    const character = string.charAt(i);
			    const charX = x + Math.cos(angle) * radius;
			    const charY = y - Math.sin(angle) * radius;
			    
			    this.ctx.save();
			    this.ctx.translate(charX, charY);
			    this.ctx.rotate(Math.PI / 2 - angle); // 旋转文字朝向圆心
			    this.ctx.fillText(character, 0, 0);
			    // this.ctx.strokeText(character, 0, 0);
			    this.ctx.restore();
			    
			    angle -= angleDecrement;
			  }
			  this.ctx.restore();
			},
			getCanvasCoord(canvas, clientX, clientY) {
				const rect = this.canvasRect;
				return {
					x: (clientX) * (canvas.width / rect.width),
					y: (clientY) * (canvas.height / rect.height)
				};
			},
			/** 启动录音 */
			handleTouchStart(e) {
				this.voiceContent = null;
				this.selectState = TO_SOUND_FLAG;
				this.$refs.popup.open();
				manager.start({
					duration: 60000,  
					lang: "zh_CN"  
				});
			},
			/** 结束录音 */
			handleTouchEnd() {
				this.$refs.popup.close();
				manager.stop();
			},
			handleTouchMove(e) {
				  e.preventDefault(); // 阻止默认行为（如页面滚动）
				  // 获取第一个触摸点的坐标
				  const touch = e.touches[0];
				  const x = touch.clientX; // 相对于视口的坐标
				  const y = touch.clientY-(this.screenHeight-this.canvasHeight);
				  this.selectState = this.calcSelectState(x, y);
			},
			handlePopupChange(e) {
				if(e.show && !this.ctx) {
					setTimeout(()=>{
						this.initCanvan();
					},100);
				}
			},
			handleLeftTouchStart(e) {
				console.log('handleLeftTouchStart')
				e.stopPropagation(); // 阻止事件冒泡
			},
			/** 初始化录音 */
			initRecord: function() {
				// 判断录音权限并提示
				// wx.getSetting({
				//   success(res) {
				//     if (!res.authSetting['scope.record']) {
				//         // 首次请求授权（会弹窗）
				//         wx.authorize({
				//             scope: 'scope.record',
				//             success() { console.log('授权成功'); },
				//             fail() { 
				//                 // 用户拒绝后，引导去设置页
				//                 wx.showModal({
				//                     title: '提示',
				//                     content: '需要录音权限，请去设置页开启',
				//                     success(res) {
				//                         if (res.confirm) wx.openSetting();
				//                     }
				//                 });
				//             }
				//         });
				//     } else {
				//         console.log('已有录音权限');
				//     }
				//   }
				// });
				manager.onStart = function(res) {
					this.selectState = TO_SOUND_FLAG;
				};
				// 识别结束事件  
				manager.onStop = (res) => {
					if(this.selectState!==CANCEL_FLAG) {
						this.voiceContent = res.result;
						this.$emit('input', {
							duration: res.duration,
							fileSize: res.fileSize,
							text: res.result,
							file: res.tempFilePath,
							button: this.selectState
						});
					}
					//"wxfile://tmp_4b1660d2ba19fca1f220a5cc658cf716.mp3"
				}  
			
				// 识别错误事件  
				manager.onError = (res) => {
					uni.showToast(res.msg);
				}
			}, 
		}
	}
</script>

<style lang="scss" scoped>
	.sound {
		width: calc(100vw - 100rpx);
		height: calc(100vh - 600rpx);
		margin-left: 50rpx;
		margin-right: 50rpx;
		margin-bottom: 100rpx;
		position: relative;
		.sound-panel {
			height: 100%;
			transition: all 0.5s ease;
			border-radius: 20rpx;
			position: absolute;
			bottom: 0;
			display: inline-flex;
			justify-content: center;
			align-items: center;
			.view {
				width: 100%;
				display: inline-flex;
				justify-content: center;
				align-items: center;
				.view {
					display: inline-block;
					vertical-align: middle;
					width: 6rpx;
					height: 30rpx;
					background-color: rgb(120, 120, 120);
					margin-right: 6rpx;
					border-radius: 50rpx;
				}
			}
			.sound-panel-cancel {
				.view {
					background-color: white;
				}
			}
		}
		.sound-panel:before { 
			position: absolute; 
			left: calc((100% - 20px) / 2); 
			bottom:-20px; 
			content:''; 
			width:0; 
			height: 0; 
			border:10px solid transparent; 
			border-top-color: greenyellow; 
			transition: all 0.5s ease;
		}
		.sound-panel-left:before {
			border-top-color: orangered; 
		}
		.sound-panel-right:before {
			left: calc((100% - 20px) / 4); 
		}
		.sound-panel-bottom {
			width: 30%;
			height: 100rpx;
			background-color: greenyellow;
			left: 35%;
		}
		.sound-panel-left {
			width: 150rpx;
			height: 100rpx;
			background-color: orangered;
			left: 0;
		}
		.sound-panel-right {
			width: 100%;
			height: 200rpx;
			background-color: greenyellow;
			left: 0;
		}
	}
	.sound-bottom {
		justify-content: center;
	}
	.sound-left {
		justify-content: flex-start;
	}
	.sound-right {
		justify-content: center;
	}
	.tools {
		bottom: 100rpx;
		position: absolute;
	}
	.left:hover, .right:hover {
		background-color: red;
	}
	.left, .right {
		height: 300rpx;
	}
	.bottom {
		height: 260rpx;
		display: inline-table;
		border-top-left-radius: 50% 150rpx;
		border-top-right-radius: 50% 150rpx;
		bottom: 0px;
		position: absolute;
	}
	.left, .right, .bottom {
		background-color: grey;
		flex: 1;
	}
	.tts-form {
		justify-content: center;
		align-items: center;
		position: absolute;
		bottom: 0;
		top: 0;
		right: 0;
		left: 0;
	}
	.line1 {
	  animation: lines 0.5s infinite ease-in-out alternate;
	}
	.line2 {
	  animation: lines 0.3s infinite ease-in-out alternate;
	}
	.line3 {
	  animation: lines 0.4s infinite ease-in-out alternate;
	}
	.line4 {
	  animation: lines 0.2s infinite ease-in-out alternate;
	}
	.line5 {
	  animation: lines 0.6s infinite ease-in-out alternate;
	}
	
	@keyframes lines {
	  from,
	  10% {
	    height: 4rpx;
	  }
	  to,
	  90% {
	    height: 40rpx;
	  }
	}
	@-webkit-keyframes lines {
	  from,
	  10% {
	    height: 4rpx;
	  }
	  to,
	  90% {
	    height: 40rpx;
	  }
	}
</style>